為了避免在使用跟hash有關的功能(ex: HashMap
、HashSet
和Hashtable
)時,因為equals
相等但hashCode
不一樣,會導致判斷物件存不存在時出現異常,如果有覆寫equals
,務必也要覆寫hashCode
。
equals
判斷相等的情況下,不管觸發幾次hashCode
,兩個物件回傳的值必須一致,如果hashCode
回傳的值不一樣,有可能會發生很弔詭的情況,明明一樣但一個可以在HashMap
、HashSet
和Hashtable
被找到,另一個卻無法被找到。equals
時用identityNumber
作為判斷的依據,但是沒有覆寫hashCode
,結果p1
和p2
雖然用equals
判斷是一樣,但hash code不一樣,要從HashMap
取出p2
值的時候,卻找不到p2
。import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
class Person {
private String identityNumber;
private int age;
public Person(String identityNumber, int age) {
this.identityNumber = identityNumber;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(identityNumber, person.identityNumber);
}
public static void main(String[] args) {
Person p1 = new Person("R12345", 30);
Person p2 = new Person("R12345", 30);
Map<Person, String> map = new HashMap<>();
map.put(p1, "Person 1");
System.out.println(p1.equals(p2)); // true
System.out.println("p1 hash code:" + p1.hashCode() + ", map get result: "+ map.get(p1)); // p1 hash code:705927765, map get result: Person 1
System.out.println("p2 hash code:" + p2.hashCode() + ", map get result: "+ map.get(p2)); // p2 hash code:366712642, map get result: null
}
}
equals
判斷兩個物件不相等,hashCode
回傳的值最好也不相等。hashCode
不相等除了可以減少hash collision,也可以提升搜尋key的效能。hashCode
的結果,不用每次都重新計算一次,能改善一些效能問題。cache的方法可以選擇使用lazily initialized去cache住hash code,宣告一個volatile的變數儲存hash code。class PersonForHash {
private boolean isAdult; //0=male, 1=female
private String name;
private int age;
private volatile int hashCode;
public PersonForHash(boolean isAdult, String name, int age) {
this.isAdult = isAdult;
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
int result = hashCode;
if (result == 0) {
result = 17;
result = 31 * result + age;
result = 31 * result + (isAdult ? 1 : 0);
result = 31 * result + (name != null ? name.hashCode() : 0);
hashCode = result;
}
return result;
}
}
明天再繼續介紹,可以遵照哪些規則覆寫hashCode
。